package com.zmn.brs.business.impl.engineer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.brs.business.impl.base.BaseBServiceImpl;
import com.zmn.brs.business.interfaces.dingtalk.DingTalkBService;
import com.zmn.brs.business.interfaces.engineer.EngineerUpaidBService;
import com.zmn.brs.business.interfaces.rule.AlarmRuleBService;
import com.zmn.brs.common.constant.BrsConst;
import com.zmn.brs.common.constant.RedisKeyConst;
import com.zmn.brs.common.enums.EventTypeEnum;
import com.zmn.brs.common.enums.SceneTypeEnum;
import com.zmn.brs.dubbo.constant.DubboConsts;
import com.zmn.brs.model.bo.rule.CacheThresholdBO;
import com.zmn.brs.model.bo.rule.CustomRuleBO;
import com.zmn.brs.model.entity.event.Event;
import com.zmn.brs.model.entity.record.EventRecord;
import com.zmn.brs.model.query.rule.EngineerRuleCustomQuery;
import com.zmn.brs.model.vo.rule.UnpaidRuleVO;
import com.zmn.brs.services.interfaces.event.EventService;
import com.zmn.brs.services.interfaces.record.EventRecordService;
import com.zmn.brs.utils.BrsUtil;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.engineer.common.dto.engineer.BaseEngineerDRO;
import com.zmn.engineer.common.model.dro.supervisor.SupervisorBasicDRO;
import com.zmn.engineer.dubbo.interfaces.engineer.EngineerListRemoteService;
import com.zmn.engineer.dubbo.interfaces.engsupervisor.SupervisorListRemoteService;
import com.zmn.mcc.common.dto.staff.StaffDRO;
import com.zmn.mcc.dubbo.interfaces.staff.StaffListRemoteService;
import com.zmn.oms.dubbo.dto.zmn.order.OrderDRO;
import com.zmn.oms.dubbo.interfaces.zmn.normal.order.ZsNormalOrderWorkRemoteService;
import com.zmn.plat.common.dictionary.StatusEnum;
import com.zmn.plat.common.dto.company.CompanyDRO;
import com.zmn.plat.dubbo.interfaces.company.BaseCompanyListRemoteService;
import com.zmn.track.common.constant.TrackConsts;
import com.zmn.track.common.dto.trackwork.QueueTrackDataDTO;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 描述： 工程师收款未支付金额监控实现
 *
 * @author chongw
 * @since 2021-07-08 9:55
 */
@Slf4j
@Service
public class EngineerUpaidBServiceImpl extends BaseBServiceImpl implements EngineerUpaidBService {

    final static String TAG = "工程师监控收款未支付金额实现" ;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private EventRecordService eventRecordService;

    @Resource
    private AlarmRuleBService alarmRuleBService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    StaffListRemoteService staffListRemoteService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    EngineerListRemoteService engineerListRemoteService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    BaseCompanyListRemoteService baseCompanyListRemoteService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    TrackWorkListRemoteService trackWorkListRemoteService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    ZsNormalOrderWorkRemoteService zsNormalOrderWorkRemoteService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    SupervisorListRemoteService supervisorListRemoteService;

    @Resource
    private DingTalkBService dingTalkBService;

    @Resource
    private EventService eventService;

    /**
     * 计算收款未支付金额
     *
     * @param eventType
     * @param queueTrackDataDTO
     * @return
     */
    @Override
    public Boolean compute(Integer eventType, QueueTrackDataDTO queueTrackDataDTO) {
        try {
            if (NumberUtil.isNullOrZero(queueTrackDataDTO.getTrackContentId())) {
                return false;
            }
            //只取trackContentId 为TrackConsts.TRACK_CONTENT_ID_ENGINEER_MONEY_NO_PAY
            if (!queueTrackDataDTO.getTrackContentId().equals(TrackConsts.TRACK_CONTENT_ID_ENGINEER_MONEY_NO_PAY)) {
                return false;
            }
            //判断工程师是否为空
            if (NumberUtil.isNullOrZero(queueTrackDataDTO.getEngineerId())) {
                return false;
            }
            //判断子公司是否为空
            if (NumberUtil.isNullOrZero(queueTrackDataDTO.getCompanyId())) {
                return false;
            }
            //判断订单ID是否为空
            if (NumberUtil.isNullOrZero(queueTrackDataDTO.getOrderId())) {
                return false;
            }
            //判断当前消息状态是否为空
            if (NumberUtil.isNullOrZero(queueTrackDataDTO.getTrackStatus())) {
                return false;
            }
            //判断当前状态是否为（待处理，已完结）
            if (!queueTrackDataDTO.getTrackStatus().equals(TrackConsts.TRACK_STATUS_PENDING)
                    && !queueTrackDataDTO.getTrackStatus().equals(TrackConsts.TRACK_STATUS_FINISHED)) {
                return false;
            }
            //根据公司ID查询子公司组件ID
            ResponseDTO<CompanyDRO> responseDTO = baseCompanyListRemoteService.getCompanyByCompanyId(queueTrackDataDTO.getCompanyId());
            if (!responseDTO.isSuccess()) {
                return false;
            }
            if (responseDTO.getData() == null) {
                return false;
            }
            CompanyDRO companyDRO = Optional.ofNullable(responseDTO.getData()).orElse(new CompanyDRO());
            //获取公司ID
            Integer companyId = companyDRO.getOrgThrId();
            //工程师ID
            Integer engineerId = queueTrackDataDTO.getEngineerId();
            Double amount = Optional.ofNullable(queueTrackDataDTO.getAmount().doubleValue()).orElse(0.0) / 100;
            //获取配置阈值key
            String configRedisKey = RedisKeyConst.getCacheRuleConfigRedisKey(eventType, companyId);
            //判断当前子公司及城市是否配置整体单量阈值
            if (!redisTemplate.hasKey(configRedisKey)) {
                log.error("[{}], 当前子公司未配置收款未支付阈值，companyId: {}", TAG, companyId);
                return false;
            }
            //配置的阈值
            CacheThresholdBO configData = this.getRuleConfigValue(configRedisKey);
            //获取当前规则状态
            Boolean statusFlag = this.checkStatus(configRedisKey);
            //状态是否已停用
            if (!statusFlag) {
                log.error("[{}], 规则ID：{} ,ThresholdId：{},规则已被停用！", TAG, configData.getRuleId(), configData.getThresholdId());
                return false;
            }
            //判断配置是否配置阈值
            if (configData == null) {
                log.error("[{}], 当前子公司未配置收款未支付配置为空，companyId: {}", TAG, companyId);
                return false;
            }
            //判断配置阈值是否为0或空
            if (NumberUtil.isNullOrZero(configData.getValue())) {
                log.error("[{}], 当前子公司未配置收款未支付配置为空，companyId: {}，阈值：{}", TAG, companyId, configData.getValue());
                return false;
            }
            ResponseDTO<Long> sumNonPayAmount = trackWorkListRemoteService.sumNonPayAmountByEngineerId(engineerId);
            log.info("工程师={},收款未支付金额={}", engineerId, sumNonPayAmount.getData());
            Double realValue = (sumNonPayAmount.getData().doubleValue() / 100);
            Double thresholdValue = configData.getValue();
            //缓存推送数据redis key   -----  新
            String todayRedisKey = RedisKeyConst.getTodayRedisKey(eventType, companyId);
            log.info("收款未支付key={}", todayRedisKey);
            //默认删除
            redisTemplate.opsForHash().delete(todayRedisKey, String.valueOf(engineerId));
            if (realValue > thresholdValue) {
                //获取工程师主管名称
                String engSupervisorName = null;
                //获取账单的产品组信息
                ResponseDTO<OrderDRO> droResponseDTO = zsNormalOrderWorkRemoteService.getOrderById(queueTrackDataDTO.getOrderId(), queueTrackDataDTO.getWorkId());
                if (droResponseDTO != null && droResponseDTO.getData() != null) {
                    OrderDRO orderDRO = droResponseDTO.getData();
                    //获取工程师主管名称
                    log.info("获取工程师信息id={}，产品组={}", queueTrackDataDTO.getEngineerId(), orderDRO.getServProductGroupId());
                    ResponseDTO<SupervisorBasicDRO> basicDROResponseDTO = supervisorListRemoteService.getSupervisorByEngineerId(queueTrackDataDTO.getEngineerId(), orderDRO.getServProductGroupId());
                    log.info("工程师信息={}", basicDROResponseDTO);
                    SupervisorBasicDRO basicDRO = basicDROResponseDTO.getData();
                    if (basicDRO != null) {
                        engSupervisorName = basicDRO.getEngSupervisorName();
                    }
                }
                //获取工程师信息
                ResponseDTO<BaseEngineerDRO> engineerDROResponseDTO = engineerListRemoteService.getEngineerByEngineerId(engineerId);
                BaseEngineerDRO engineerDRO = engineerDROResponseDTO.getData();
                //获取工程师真实姓名
                String realName = engineerDRO.getRealname();
                log.info("[{}], companyId：{}, engineerId：{} ,已触发工程师收款未支付监控预警！实际值：{}，阈值：{}", TAG, companyId, engineerId, realValue, thresholdValue);
                JSONObject expandJson = new JSONObject();
                expandJson.put("realValue", realValue);
                expandJson.put("thresholdValue", thresholdValue);
                expandJson.put("engineerId", engineerId);
                expandJson.put("engineerName", realName);
                expandJson.put("engSupervisorName", engSupervisorName);
                EventRecord record = EventRecord.builder()
                        .objectId(engineerId.longValue())
                        .objectName(realName)
                        .thresholdId(configData.getThresholdId())
                        .sceneType(SceneTypeEnum.ENGINEER_TARGET.getTypeId())
                        .eventCode(configData.getEventCode())
                        .messageSend(GlobalConsts.NO)
                        .realName(configData.getThresholdName())
                        .expand(expandJson.toJSONString())
                        .createTime(DateUtil.getNow())
                        .monitorVersion(todayRedisKey)
                        .build();
                //保存事件监控数据
                Integer flag = eventRecordService.insert(record);
                if (flag > 0) {
                    log.info("[{}], companyId：{} ，engineerId：{} ，保存事件记录成功！！！", TAG, companyId, engineerId);
                } else {
                    log.error("[{}], companyId：{}，engineerId：{} ，保存事件记录失败！！！", TAG, companyId, engineerId);
                }
                //存放满足条件的信息
                log.info("{}记录了{}", todayRedisKey, expandJson);
                redisTemplate.opsForHash().put(todayRedisKey, String.valueOf(engineerId), expandJson.toJSONString());
                redisTemplate.expire(todayRedisKey, 7, TimeUnit.DAYS);
            }
            return true;
        } catch (Exception e) {
            log.error("[{}], 参数：{}，工程师收款未支付金额监控异常，异常信息：", TAG, JSON.toJSONString(queueTrackDataDTO), e);
        }
        return false;
    }

    /**
     * 工程师收款未支付金额消息推送
     *
     * @param eventType
     * @param smsRuleId
     * @param pushTopic
     */
    public void pushJob(Integer eventType, Integer smsRuleId, String pushTopic) {
        EngineerRuleCustomQuery query = EngineerRuleCustomQuery.builder()
                .eventType(eventType)
                .build();
        //查询收款未支付金额规则
        List<CustomRuleBO> unpaidRuleList = alarmRuleBService.listRuleByEventQuery(query);
        unpaidRuleList.forEach(o -> {
            if (StatusEnum.DISABLE.getCode().equals(o.getRealStatus())) {
                log.error("[{}], 规则ID：{} ,ThresholdId：{},规则已被停用！", TAG, o.getRuleId(), o.getThresholdId());
                return;
            }
            UnpaidRuleVO ruleVO = JSONObject.parseObject(o.getThresholdValue(), UnpaidRuleVO.class);
            log.info("[{}]阈值信息={}", ruleVO);
            Integer companyId = ruleVO.getOrgThrId();
            String companyName = ruleVO.getOrgThrName();
            Double thresholdValue = ruleVO.getValue();
            ruleVO.setThresholdId(o.getThresholdId());
            //缓存推送数据redis key
            String todayRedisKey = RedisKeyConst.getTodayRedisKey(eventType, companyId);
            //获取预警数据
            Map<Object, Object> warnData = Optional.ofNullable(redisTemplate.opsForHash().entries(todayRedisKey)).orElse(new HashMap<>());
            log.info("[{}]预警缓存数据={}", TAG, JSONObject.toJSONString(warnData));
            if (warnData.isEmpty()) {
                log.info("[{}], 规则ID：{} ,ThresholdId：{}，子公司：{}，当前子公司无派单客单价监控数据！！！", TAG, o.getRuleId(), o.getThresholdId(), companyId);
                return;
            }
            StringBuffer sb = new StringBuffer();
            //工程师主管名称
            List<String> listName = new ArrayList<>();
            List<UnpaidRuleVO> ruleVOList = new ArrayList<>();
            warnData.forEach((k, v) -> {
                if (v != null) {
                    UnpaidRuleVO unpaidRuleVO = JSONObject.parseObject(v.toString(), UnpaidRuleVO.class);
                    if (unpaidRuleVO != null) {
                        Integer engineerId = unpaidRuleVO.getEngineerId();
                        ResponseDTO<Long> sumNonPayAmount = trackWorkListRemoteService.sumNonPayAmountByEngineerId(engineerId);
                        log.info("发送消息获取最新的金额，工程师={},收款未支付金额={}", engineerId, sumNonPayAmount.getData());
                        Double realValue = (sumNonPayAmount.getData().doubleValue() / 100);
                        if (realValue > thresholdValue) {
                            unpaidRuleVO.setRealValue(realValue);
                            ruleVOList.add(unpaidRuleVO);
                            String engSupervisorName = unpaidRuleVO.getEngSupervisorName();
                            engSupervisorName = (engSupervisorName == null ? "" : engSupervisorName);
                            if (!listName.contains(engSupervisorName)) {
                                listName.add(engSupervisorName);
                            }
                        } else {
                            log.info("不满足阈值删除，工程师={}数据", engineerId);
                            redisTemplate.opsForHash().delete(todayRedisKey, String.valueOf(engineerId));
                        }
                    }
                }
            });
            log.info("工程师主管名称={}", listName);
            for (String item : listName) {
                sb.append(String.format("工程师所属主管：%s\n", (item.equals("") ? "暂无" : item)));
                ruleVOList.forEach(unpaidRuleVO -> {
                    if (unpaidRuleVO != null) {
                        String engSupervisorName = unpaidRuleVO.getEngSupervisorName();
                        engSupervisorName = (engSupervisorName == null ? "" : engSupervisorName);
                        if (item.equals(engSupervisorName)) {
                            Double realValue = unpaidRuleVO.getRealValue();
                            log.info("阈值{},实际值{}", thresholdValue, realValue);
                            //当天数据大于配置阈值，则预警
                            if (realValue > thresholdValue) {
                                //Integer engineerId = Integer.parseInt(k.toString());
                                //获取工程师信息
                                //获取工程师真实姓名
                                String realName = unpaidRuleVO.getEngineerName();
                                String content = String.format("「%s」 实际收款未支付金额：%s \n", realName, BrsUtil.formatDoubleToStr(unpaidRuleVO.getRealValue()));
                                sb.append(content);
                            }
                        }
                    }
                });
            }
            if (sb != null && StringUtil.isNotBlank(sb.toString())) {
                StringBuffer msg = new StringBuffer();
                msg.append("【工程师收款未支付金额预警】\n");
                msg.append(String.format("%s以下工程师实际收款未支付金额已超过%s，请前往啄木鸟管理平台-工单管理菜单中的跟单管理-跟单列表中进行查看，可在跟单列表中点击精准查询，选择跟单内容为：工程师收款未支付并输入工程师姓名查询其收款未支付跟单详情。\n", companyName, BrsUtil.formatDoubleToStr(thresholdValue)));
                msg.append(sb);
                msg.append(String.format("%s数据", DateUtil.getNowFormatted().replace(" ", " 截止 ")));
                log.info("thresholdId={},ruleVO={}", o.getThresholdId(), ruleVO);
                //获取群Id
                Integer robotId = ruleVO.getRobotId();
                if (NumberUtil.isNullOrZero(robotId)) {
                    log.info("robotId={}为空，取默认群", robotId);
                    Event event = Optional.ofNullable(eventService.findByEventCode(o.getEventCode())).orElse(Event.builder().build());
                    robotId = event.getRobotId();
                }
                dingTalkBService.sendDingtalkGroup(robotId, msg.toString());
                String receiverIdStr = ruleVO.getReceiverId();
                log.info("配置发送钉钉人员={}", receiverIdStr);
                if (!(StringUtil.isBlank(receiverIdStr))) {
                    StringBuilder dtalkIdBuilder = new StringBuilder();
                    String[] receiverIds = null;
                    if (receiverIdStr.contains(BrsConst.COMMA)) {
                        //多个用户
                        receiverIds = receiverIdStr.split(BrsConst.COMMA);
                    } else {
                        //单个用户
                        receiverIds = new String[]{receiverIdStr};
                    }
                    for (int i = 0; i < receiverIds.length; i++) {
                        Integer receiverId = Integer.valueOf(receiverIds[i]);
                        //获取接收人信息
                        ResponseDTO<StaffDRO> staffDTO = staffListRemoteService.getStaff(receiverId);
                        if (!staffDTO.isSuccess()) {
                            log.error("[{}], 获取接收人信息失败，staffId：{}", TAG, receiverId);
                            continue;
                        }
                        StaffDRO receiverStaff = Optional.ofNullable(staffDTO.getData()).orElse(new StaffDRO());
                        String dtalkId = receiverStaff.getDTalkId();
                        if (dtalkIdBuilder.length() > 0) {
                            dtalkIdBuilder.append(",");
                        }
                        dtalkIdBuilder.append(dtalkId);
                        if (StringUtil.isBlank(dtalkId)) {
                            log.error("[{}], 获取接收人钉钉ID为空，staffId：{}", TAG, receiverId);
                        }
                    }
                    if (dtalkIdBuilder.length() > 0) {
                        JSONObject data = new JSONObject();
                        /* data.put("eventName" , EventTypeEnum.ENGINEER_UNPAID.getTypeName());
                         data.put("companyName" , companyName);
                         data.put("thresholdValue" , String.format("已超过【目标值%s】", thresholdValue));*/
                        data.put("contentMsg", msg.toString());
                        dingTalkBService.sendDingTalk(dtalkIdBuilder.toString(), data.toJSONString(), smsRuleId, pushTopic);
                    }
                }
            }


        });

    }


}
